package com.dragons.dragonsvf.utils.idbuilder;

import java.net.InetAddress;
import java.net.UnknownHostException;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.time.Instant;
import java.util.Base64;
import java.util.UUID;
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.atomic.AtomicLong;


/**
 * @author dragons
 * @version 1.0.0
 * @description: 用以生成不重复的ID  唯一ID生成工具类（线程安全）  包含10种不同的唯一ID生成策略
 * @date 2025/3/14 15:03
 */
public class IdUtil {

    /**
     *10种生成策略：
     *
     * UUID精简版
     * 时间戳+随机数
     * 改进版雪花算法
     * 哈希算法生成
     * Base64安全随机
     * 机器特征组合
     * 人类可读编码
     * 递增序列号
     * 混合加密ID
     * 纳米时间组合
     * 核心功能特性：
     *
     * 长度控制：所有方法都支持参数控制输出长度
     * 唯一性保证：结合时间戳、随机数、机器特征、序列号等多种因素
     * 线程安全：使用线程安全类（AtomicLong、ThreadLocalRandom）
     * 高性能：避免同步锁，使用轻量级算法
     * 特殊场景优化：
     *
     * 分布式系统（雪花算法、机器特征）
     * 高并发场景（时间戳+随机数组合）
     * 安全性需求（SHA3加密哈希）
     * 人类可读需求（可读字符组合）
     * 扩展性设计：
     *
     * 方便添加新的生成策略
     * 可配置字符集（如humanReadableCode方法）
     * 支持自定义截断策略
     * 使用示例输出：
     * text
     * UUID:         7b9d3f5a7f7d4f6c
     * Timestamp:    171723456789012345
     * Snowflake:    18ab3c5d9e2
     * Hashed:       a1b2c3d4e5f6
     * Base64:       ABcDefGHiJ
     * Machine ID:   192-4732-123456789
     * Readable:     A3B9CD2F
     * Incremental:  0000000123
     * Encrypted:    mBcNtRkLpXqW7vzY8u9A0s1D
     * NanoTime:     18ab3c5d9e2f4a6b
     */

    // 分布式环境需确保不同的workerId
    private static final int DEFAULT_WORKER_ID = 1;
    private static final AtomicLong SEQUENCE = new AtomicLong(0);
    private static final int IP_PART;

    static {
        int tempIpPart = 0;
        try {
            String ip = InetAddress.getLocalHost().getHostAddress();
            String[] segments = ip.split("\\.");
            if (segments.length == 4) {
                tempIpPart = Integer.parseInt(segments[3]) & 0xFF;
            }
        } catch (UnknownHostException | NumberFormatException | ArrayIndexOutOfBoundsException e) {
            tempIpPart = new SecureRandom().nextInt(256); // 回退随机值
        }
        IP_PART = tempIpPart;
    }

    // 方法1：安全UUID
    public static String uuid(int length) {
        validateLength(length, 32);
        return truncate(UUID.randomUUID().toString().replace("-", ""), length);
    }

    // 方法2：时间戳随机组合（带异常处理）
    public static String timestampRandom(int length) {
        validateLength(length, 1);
        try {
            long ts = Instant.now().toEpochMilli();
            int random = ThreadLocalRandom.current().nextInt(10000, 99999);
            return truncate(ts + "" + random, length);
        } catch (Exception e) {
            return fallbackId(length); // 降级方案
        }
    }

    // 方法3：改进雪花算法
    public static synchronized String snowflakeId(int length) {
        validateLength(length, 8);
        try {
            long timestamp = System.currentTimeMillis();
            long sequence = SEQUENCE.incrementAndGet() & 0xFFF;
            long id = (timestamp << 22) | (IP_PART << 12) | sequence;
            return truncate(Long.toHexString(id), length);
        } catch (Exception e) {
            throw new IdGenerationException("Snowflake ID generation failed", e);
        }
    }

    // 方法4：安全哈希ID（异常封装）
    public static String hashId(String input, int length) {
        validateInput(input);
        validateLength(length, 1);
        try {
            MessageDigest digest = MessageDigest.getInstance("SHA-256");
            byte[] hashBytes = digest.digest(input.getBytes(StandardCharsets.UTF_8));
            return truncate(bytesToHex(hashBytes), length);
        } catch (NoSuchAlgorithmException e) {
            throw new IdGenerationException("Hash algorithm not available", e);
        }
    }

    // 方法5：Base64安全随机（参数校验）
    public static String base64Random(int length) {
        validateLength(length, 1);
        try {
            byte[] randomBytes = new byte[length * 2]; // 双倍长度保证截取后熵足够
            new SecureRandom().nextBytes(randomBytes);
            String encoded = Base64.getUrlEncoder().withoutPadding().encodeToString(randomBytes);
            return truncate(encoded, length);
        } catch (Exception e) {
            return fallbackId(length);
        }
    }

    // 参数校验方法
    private static void validateLength(int length, int min) {
        if (length < min) {
            throw new IllegalArgumentException("Length must be at least " + min);
        }
    }

    private static void validateInput(String input) {
        if (input == null || input.isEmpty()) {
            throw new IllegalArgumentException("Input cannot be null or empty");
        }
    }

    // 异常降级方案
    private static String fallbackId(int length) {
        return truncate(Long.toHexString(System.nanoTime()), length);
    }

    // 自定义运行时异常
    private static class IdGenerationException extends RuntimeException {
        public IdGenerationException(String message, Throwable cause) {
            super(message, cause);
        }
    }

    /**
     * 方法6：机器标识+进程ID+时间戳
     * 适用场景：多节点环境防冲突
     */
    public static String machineSpecificId(int length) {
        String pid = getProcessId();
        long timestamp = System.nanoTime();
        return truncate(IP_PART + pid + timestamp, length);
    }

    /**
     * 方法7：可读字符随机组合
     * 适用场景：需要人类可读的代码
     */
    public static String humanReadableCode(int length) {
        String characters = "ABCDEFGHJKLMNPQRSTUVWXYZ23456789";
        StringBuilder sb = new StringBuilder(length);
        for (int i = 0; i < length; i++) {
            int index = ThreadLocalRandom.current().nextInt(characters.length());
            sb.append(characters.charAt(index));
        }
        return sb.toString();
    }

    /**
     * 方法8：递增序列号（带校验位）
     * 适用场景：需要连续有序的编号
     */
    public static String incrementalId(int length) {
        long num = SEQUENCE.incrementAndGet();
        String base = String.format("%0" + (length - 1) + "d", num % (long) Math.pow(10, length - 1));
        return base + luhnCheckDigit(base);
    }

    /**
     * 方法9：混合加密ID（时间+随机+哈希）
     * 适用场景：高安全性要求
     */
    public static String encryptedId(int length) throws Exception {
        String raw = System.currentTimeMillis() + "-" + new SecureRandom().nextLong();
        MessageDigest digest = MessageDigest.getInstance("SHA3-256");
        byte[] hash = digest.digest(raw.getBytes());
        return truncate(Base64.getEncoder().encodeToString(hash), length);
    }

    /**
     * 方法10：纳米时间+线程ID组合
     * 适用场景：单机高性能场景
     */
    public static String nanoTimeId(int length) {
        long nano = System.nanoTime();
        long threadId = Thread.currentThread().getId();
        String combined = Long.toHexString(nano) + Long.toHexString(threadId);
        return truncate(combined, length);
    }

    // 以下是工具方法

    /**
     * 安全截断字符串（保持数据完整性）
     */
    private static String truncate(String input, int maxLength) {
        if (input == null) {
            return null;
        }
        return input.length() > maxLength ? input.substring(0, maxLength) : input;
    }

    /**
     * 字节数组转十六进制
     */
    private static String bytesToHex(byte[] bytes) {
        StringBuilder sb = new StringBuilder();
        for (byte b : bytes) {
            sb.append(String.format("%02x", b));
        }
        return sb.toString();
    }

    /**
     * 生成Luhn校验码
     */
    private static int luhnCheckDigit(String number) {
        int sum = 0;
        boolean alternate = false;
        for (int i = number.length() - 1; i >= 0; i--) {
            int n = Integer.parseInt(number.substring(i, i + 1));
            if (alternate) {
                n *= 2;
                if (n > 9) {
                    n = (n % 10) + 1;
                }
            }
            sum += n;
            alternate = !alternate;
        }
        return (sum * 9) % 10;
    }

    /**
     * 获取进程ID（兼容多平台）
     */
    private static String getProcessId() {
        String processName = java.lang.management.ManagementFactory.getRuntimeMXBean().getName();
        return processName.split("@")[0];
    }

    // 示例使用
    public static void main(String[] args) throws Exception {
        System.out.println("UUID:         " + uuid(16));
        System.out.println("Timestamp:    " + timestampRandom(18));
        System.out.println("Snowflake:    " + snowflakeId(20));
        System.out.println("Hashed:       " + hashId("input", 12));
        System.out.println("Base64:       " + base64Random(10));
        System.out.println("Machine ID:   " + machineSpecificId(15));
        System.out.println("Readable:     " + humanReadableCode(8));
        System.out.println("Incremental:  " + incrementalId(10));
        System.out.println("Encrypted:    " + encryptedId(24));
        System.out.println("NanoTime:     " + nanoTimeId(16));
    }
}